/**
 * 
 */
package com.atomic.test.example.utils.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author zhouhongyang@zbj.com
 *
 */
public class GsonFactory {
	private static volatile Gson gson;
	private static final Logger logger = LoggerFactory.getLogger(GsonFactory.class);

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Gson getInstance() {
		if (gson != null)
			return gson;
		synchronized (GsonFactory.class) {
			if (gson != null)
				return gson;
			GsonBuilder gsonBuilder = new GsonBuilder();

			gsonBuilder.registerTypeAdapter(Date.class, new DateTimeSerializer());
			gsonBuilder.registerTypeAdapter(Date.class, new DateTimeDeserializer());

			// FOLLOWING LINE NOT WORK
			// because ObjectTypeAdapter always before the following adapter
			gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());

			Gson gson = gsonBuilder.create();

			// http://stackoverflow.com/questions/23695649/gson-custom-serialization
			// 通过反射将NaturalDeserializer(index=3)调到最前面,
			try {
				Field f = Gson.class.getDeclaredField("factories");
				f.setAccessible(true);
				List d = (List) f.get(gson);
				List list = new ArrayList(d.size());
				list.addAll(d);
				Object temp = list.get(3);
				for (int i = 3; i > 0; i--) {
					list.set(i, list.get(i - 1));
				}
				list.set(0, temp);
				list = Collections.unmodifiableList(list);
				f.set(gson, list);

				GsonFactory.gson = gson;
			} catch (Exception e) {
				logger.error("regist customer TypeAdapter to gson fail", e);
			}
			return gson;
		}
	}
}
